print("缓慢的循环操作")

import numpy as np
from numpy.core.arrayprint import printoptions
from numpy.lib.function_base import percentile

np.random.seed(0)

def compute_reciprocals(values):
    output = np.empty(len(values))
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    return output

values = np.random.randint(1,10, size=5)
print(values)
print(compute_reciprocals(values))
#事实上，这里的处理瓶颈并不是运算本身，而是 CPython 在每次循环时必须做数据类
# 型的检查和函数的调度。每次进行倒数运算时，Python 首先检查对象的类型，并且动态查
# 找可以使用该数据类型的正确函数。如果我们在编译代码时进行这样的操作，那么就能在
# 代码执行之前知晓类型的声明，结果的计算也会更加有效率。
big_array = np.random.randint(1,100, size=1000000)
# %timeit compute_reciprocals(big_array)

# NumPy 为很多类型的操作提供了非常方便的、静态类型的、可编译程序的接口，也被称作
# 向量操作。你可以通过简单地对数组执行操作来实现，这里对数组的操作将会被用于数组
# 中的每一个元素。这种向量方法被用于将循环推送至 NumPy 之下的编译层，这样会取得
# 更快的执行效率。
print(compute_reciprocals(values))
print(1.0/values)

# NumPy 中的向量操作是通过通用函数实现的。通用函数的主要目的是对 NumPy 数组中的
# 值执行更快的重复操作。它非常灵活，前面我们看过了标量和数组的运算，但是也可以对
# 两个数组进行运算：
test1 = np.arange(5)
test2 = np.arange(1,6)
print(test1)
print(test2)
print(test1/test2)  #对应位置的元素相除

print("多为数组运算")
x = np.arange(9).reshape((3,3))
print(2**x)

print("通用函数有两种存在形式：一元通用函数（unary ufunc）对单个输入操作，二元通用函数\
    （binary ufunc）对两个输入操作。")
x = np.arange(4)
print("x  =", x)
print("x+5", x+5)
print("x//2 ", x//2)
print("所有这些算术运算符都是 NumPy 内置函数的简单封装器，例如 + 运算符就是一个 add 函数的封装器：")
print(np.add(x, 2))

print("绝对值：正如 NumPy 能理解 Python 内置的运算操作，NumPy 也可以理解 Python 内置的绝对值函数： ")
x = np.array([-2,-1,0,1,2])
print(abs(x)) #应的 NumPy 通用函数是 np.absolute，该函数也可以用别名 np.abs 来访问：
print(np.absolute(x))
print(np.abs(x))
x = np.array([3-4j,4-3j,2+0j,0+1j])
print(np.abs(x))

print("三角函数： ")
theta = np.linspace(0, np.pi, 3)
print("theta= ", theta)
print("sin(theta)= ", np.sin(theta))

x = [-1,0,1]
print("arcsin(x): ", np.arcsin(x))

print("指数和对数")
x = [1,2,3]
print("e^x = ", np.exp(x))
print("2^x = ", np.exp2(x))
print("3^x = ", np.power(3, x))
x = [1,2,4,10]
print("ln(x) = ", np.log(x))
print("log2(x) = ", np.log2(x))
print("log10(x) = ", np.log10(x))
print("较好的精度")
x = [0, 0.001, 0.01, 0.1]
print("exp(x) - 1= ", np.expm1(x))
print("log(1+x) = ", np.log1p(x) )

print("还有一个更加专用，也更加晦涩的通用函数优异来源是子模块 scipy.special。如果你希\
    望对你的数据进行一些更晦涩的数学计算，scipy.special 可能包含了你需要的计算函数。\
        这些函数能列一个长长的列表，下面的代码片段展示了一些可能在统计学中用到的函数：")
from scipy import special

x= [1,5,10]
print("gamma(x) =  ", special.gamma(x))
print("ln | gamma(x) | = ", special.gammaln(x))
print("beta(x,2) = ", special.beta(x,2))

print("高级的通用函数特性")
x = np.arange((5))
y = np.empty(5)
np.multiply(x, 10, out=y)
print(y)
y = np.zeros(10)
np.power(2,x,out=y[::2])
print(y)

print("二元通用函数有些非常有趣的聚合功能")
x = np.arange(1,6)
np.add.reduce(x)  #所有元素相加
print(np.multiply.reduce(x)) #所有元素相乘
print("如果需要存储每次计算的中间结果，可以使用 accumulate")
print(np.add.accumulate(x))
print(np.multiply.accumulate(x))

print("外积： 最后，任何通用函数都可以用 outer 方法获得两个不同输入数组所有元素对的函数运算结果。")
x = np.arange(1,6)
print(np.multiply.outer(x,x))

print("数组值求和")
import numpy as np

L = np.random.random(100)
print(sum(L))
print(np.sum(L))
print(np.max(L))
print(np.min(L))
print(L.max())
print(L.min())
print(L.sum())

print("多维度聚合")
M = np.random.random((3,4))
print(M)
print(M.sum())
print(M.min(axis=0))
print("其他语言的用户会对轴的指定方式比较困惑。axis 关键字指定的是数组将会被折叠的维\
    度，而不是将要返回的维度。因此指定 axis=0 意味着第一个轴将要被折叠——对于二维数\
        组，这意味着每一列的值都将被聚合。")
print("NumPy 提供了很多其他聚合函数，但是这里不会详细地介绍它们。另外，大多数的聚合都\
    有对 NaN 值的安全处理策略（NaN-safe），即计算时忽略所有的缺失值，这些缺失值即特殊\
        的 IEEE 浮点型 NaN 值")
